<!DOCTYPE html>



  


<html class="theme-next mist use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="lnmp, thinkphp,运维" />










<meta property="og:type" content="website">
<meta property="og:title" content="LYJ&#39;s NOTES">
<meta property="og:url" content="https://www.lyj210.cn/page/4/index.html">
<meta property="og:site_name" content="LYJ&#39;s NOTES">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="LYJ&#39;s NOTES">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    version: '5.1.3',
    sidebar: {"position":"left","display":"always","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://www.lyj210.cn/page/4/"/>





  <title>LYJ's NOTES</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left 
  page-home">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">LYJ's NOTES</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <h1 class="site-subtitle" itemprop="description"></h1>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://www.lyj210.cn/2018/12/13/CompletableFuture/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="LYJ">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="LYJ's NOTES">
    </span>

    
      <header class="post-header">

        
        
          <h2 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/12/13/CompletableFuture/" itemprop="url">CompletableFuture</a></h2>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-12-13T15:47:24+08:00">
                2018-12-13
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="Java-8-CompletableFuture-教程"><a href="#Java-8-CompletableFuture-教程" class="headerlink" title="Java 8 CompletableFuture 教程"></a>Java 8 CompletableFuture 教程</h1><p>Java 8 有大量的新特性和增强如 <a href="https://link.juejin.im/?target=https%3A%2F%2Fwww.callicoder.com%2Fjava-lambda-expression-tutorial%2F" target="_blank" rel="noopener">Lambda 表达式</a>，<a href="https://link.juejin.im/?target=https%3A%2F%2Fdocs.oracle.com%2Fjavase%2F8%2Fdocs%2Fapi%2Fjava%2Futil%2Fstream%2Fpackage-summary.html" target="_blank" rel="noopener">Streams</a>，<a href="https://link.juejin.im/?target=https%3A%2F%2Fdocs.oracle.com%2Fjavase%2F8%2Fdocs%2Fapi%2Fjava%2Futil%2Fconcurrent%2FCompletableFuture.html" target="_blank" rel="noopener">CompletableFuture</a>等。在本篇文章中我将详细解释清楚CompletableFuture以及它所有方法的使用。</p>
<h2 id="什么是CompletableFuture？"><a href="#什么是CompletableFuture？" class="headerlink" title="什么是CompletableFuture？"></a>什么是CompletableFuture？</h2><p>在Java中CompletableFuture用于异步编程，异步编程是编写非阻塞的代码，运行的任务在一个单独的线程，与主线程隔离，并且会通知主线程它的进度，成功或者失败。</p>
<p>在这种方式中，主线程不会被阻塞，不需要一直等到子线程完成。主线程可以并行的执行其他任务。</p>
<p>使用这种并行方式，可以极大的提高程序的性能。</p>
<h2 id="Future-vs-CompletableFuture"><a href="#Future-vs-CompletableFuture" class="headerlink" title="Future vs CompletableFuture"></a>Future vs CompletableFuture</h2><p>CompletableFuture 是 <a href="https://link.juejin.im/?target=https%3A%2F%2Fdocs.oracle.com%2Fjavase%2F7%2Fdocs%2Fapi%2Fjava%2Futil%2Fconcurrent%2FFuture.html" target="_blank" rel="noopener">Future API</a>的扩展。</p>
<p>Future 被用于作为一个异步计算结果的引用。提供一个 <code>isDone()</code> 方法来检查计算任务是否完成。当任务完成时，<code>get()</code> 方法用来接收计算任务的结果。</p>
<p>从 <a href="https://link.juejin.im/?target=https%3A%2F%2Fwww.callicoder.com%2Fjava-callable-and-future-tutorial%2F" target="_blank" rel="noopener">Callbale和 Future 教程</a>可以学习更多关于 Future 知识.</p>
<p>Future API 是非常好的 Java 异步编程进阶，但是它缺乏一些非常重要和有用的特性。</p>
<h2 id="Future-的局限性"><a href="#Future-的局限性" class="headerlink" title="Future 的局限性"></a>Future 的局限性</h2><ol>
<li>不能手动完成 当你写了一个函数，用于通过一个远程API获取一个电子商务产品最新价格。因为这个 API 太耗时，你把它允许在一个独立的线程中，并且从你的函数中返回一个 Future。现在假设这个API服务宕机了，这时你想通过该产品的最新缓存价格手工完成这个Future 。你会发现无法这样做。</li>
<li>Future 的结果在非阻塞的情况下，不能执行更进一步的操作 Future 不会通知你它已经完成了，它提供了一个阻塞的 <code>get()</code> 方法通知你结果。你无法给 Future 植入一个回调函数，当 Future 结果可用的时候，用该回调函数自动的调用 Future 的结果。</li>
<li>多个 Future 不能串联在一起组成链式调用 有时候你需要执行一个长时间运行的计算任务，并且当计算任务完成的时候，你需要把它的计算结果发送给另外一个长时间运行的计算任务等等。你会发现你无法使用 Future 创建这样的一个工作流。</li>
<li>不能组合多个 Future 的结果 假设你有10个不同的Future，你想并行的运行，然后在它们运行未完成后运行一些函数。你会发现你也无法使用 Future 这样做。</li>
<li>没有异常处理 Future API 没有任务的异常处理结构居然有如此多的限制，幸好我们有CompletableFuture，你可以使用 CompletableFuture 达到以上所有目的。</li>
</ol>
<p>CompletableFuture 实现了 <code>Future</code> 和 <code>CompletionStage</code>接口，并且提供了许多关于创建，链式调用和组合多个 Future 的便利方法集，而且有广泛的异常处理支持。</p>
<h2 id="创建-CompletableFuture"><a href="#创建-CompletableFuture" class="headerlink" title="创建 CompletableFuture"></a>创建 CompletableFuture</h2><p><strong>1. 简单的例子</strong> 可以使用如下无参构造函数简单的创建 CompletableFuture：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture&lt;String&gt; completableFuture = <span class="keyword">new</span> CompletableFuture&lt;String&gt;();</span><br></pre></td></tr></table></figure>
<p>这是一个最简单的 CompletableFuture，想获取CompletableFuture 的结果可以使用 <code>CompletableFuture.get()</code> 方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String result = completableFuture.get()</span><br></pre></td></tr></table></figure>
<p><code>get()</code> 方法会一直阻塞直到 Future 完成。因此，以上的调用将被永远阻塞，因为该Future一直不会完成。</p>
<p>你可以使用 <code>CompletableFuture.complete()</code> 手工的完成一个 Future：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">completableFuture.complete(<span class="string">"Future's Result"</span>)</span><br></pre></td></tr></table></figure>
<p>所有等待这个 Future 的客户端都将得到一个指定的结果，并且 <code>completableFuture.complete()</code>之后的调用将被忽略。</p>
<p><strong>2. 使用 runAsync() 运行异步计算</strong> 如果你想异步的运行一个后台任务并且不想改任务返回任务东西，这时候可以使用 <code>CompletableFuture.runAsync()</code>方法，它持有一个<a href="https://link.juejin.im/?target=https%3A%2F%2Fdocs.oracle.com%2Fjavase%2F7%2Fdocs%2Fapi%2Fjava%2Flang%2FRunnable.html" target="_blank" rel="noopener">Runnable </a>对象，并返回 <code>CompletableFuture&lt;Void&gt;</code>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Run a task specified by a Runnable Object asynchronously.</span></span><br><span class="line">CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// Simulate a long-running Job</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"I'll run in a separate thread than the main thread."</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Block and wait for the future to complete</span></span><br><span class="line">future.get()</span><br></pre></td></tr></table></figure>
<p>你也可以以 lambda 表达式的形式传入 Runnable 对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Using Lambda Expression</span></span><br><span class="line">CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(() -&gt; &#123;</span><br><span class="line">    <span class="comment">// Simulate a long-running Job   </span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    System.out.println(<span class="string">"I'll run in a separate thread than the main thread."</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>在本文中，我使用lambda表达式会比较频繁，如果以前你没有使用过，建议你也多使用lambda 表达式。</p>
<p><strong>3. 使用 supplyAsync() 运行一个异步任务并且返回结果</strong> 当任务不需要返回任何东西的时候， <code>CompletableFuture.runAsync()</code> 非常有用。但是如果你的后台任务需要返回一些结果应该要怎么样？</p>
<p><code>CompletableFuture.supplyAsync()</code> 就是你的选择。它持有<code>supplier&lt;T&gt;</code> 并且返回<code>CompletableFuture&lt;T&gt;</code>，<code>T</code> 是通过调用 传入的supplier取得的值的类型。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Run a task specified by a Supplier object asynchronously</span></span><br><span class="line">CompletableFuture&lt;String&gt; future = CompletableFuture.supplyAsync(<span class="keyword">new</span> Supplier&lt;String&gt;() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">get</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Result of the asynchronous computation"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Block and get the result of the Future</span></span><br><span class="line">String result = future.get();</span><br><span class="line">System.out.println(result);</span><br></pre></td></tr></table></figure>
<p><code>Supplier&lt;T&gt;</code> 是一个简单的函数式接口，表示supplier的结果。它有一个<code>get()</code>方法，该方法可以写入你的后台任务中，并且返回结果。</p>
<p>你可以使用lambda表达式使得上面的示例更加简明：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Using Lambda Expression</span></span><br><span class="line">CompletableFuture&lt;String&gt; future = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Result of the asynchronous computation"</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p><strong>一个关于Executor 和Thread Pool笔记</strong> </p>
<p>CompletableFuture的方法如果以<code>Async</code>结尾，它会异步的执行(没有指定executor的情况下)， 异步执行通过<a href="https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ForkJoinPool.html" target="_blank" rel="noopener">ForkJoinPool</a>实现， 它使用守护线程去执行任务。注意这是CompletableFuture的特性， 其它CompletionStage可以override这个默认的行为。CompletableFuture API 的所有方法都有两个变体一个接受<code>Executor</code>作为参数，另一个不接受<code>Executor</code>：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Variations of runAsync() and supplyAsync() methods</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> CompletableFuture&lt;Void&gt;  <span class="title">runAsync</span><span class="params">(Runnable runnable)</span></span></span><br><span class="line"><span class="function"><span class="keyword">static</span> CompletableFuture&lt;Void&gt;  <span class="title">runAsync</span><span class="params">(Runnable runnable, Executor executor)</span></span></span><br><span class="line"><span class="function"><span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier)</span></span></span><br><span class="line"><span class="function"><span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier, Executor executor)</span></span></span><br></pre></td></tr></table></figure>
<p>创建一个线程池，并传递给其中一个方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Executor executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line">CompletableFuture&lt;String&gt; future = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Result of the asynchronous computation"</span>;</span><br><span class="line">&#125;, executor);</span><br></pre></td></tr></table></figure>
<h2 id="在-CompletableFuture-转换和运行"><a href="#在-CompletableFuture-转换和运行" class="headerlink" title="在 CompletableFuture 转换和运行"></a>在 CompletableFuture 转换和运行</h2><p><code>CompletableFuture.get()</code>方法是阻塞的。它会一直等到Future完成并且在完成后返回结果。 但是，这是我们想要的吗？对于构建异步系统，我们应该附上一个回调给CompletableFuture，当Future完成的时候，自动的获取结果。 如果我们不想等待结果返回，我们可以把需要等待Future完成执行的逻辑写入到回调函数中。</p>
<p>可以使用 <code>thenApply()</code>, <code>thenAccept()</code> 和<code>thenRun()</code>方法附上一个回调给CompletableFuture。</p>
<p><strong>1. thenApply()</strong> 可以使用 <code>thenApply()</code> 处理和改变CompletableFuture的结果。持有一个<code>Function&lt;R,T&gt;</code>作为参数。<code>Function&lt;R,T&gt;</code>是一个简单的函数式接口，接受一个T类型的参数，产出一个R类型的结果。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Create a CompletableFuture</span></span><br><span class="line">CompletableFuture&lt;String&gt; whatsYourNameFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">   <span class="keyword">try</span> &#123;</span><br><span class="line">       TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">   &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> <span class="string">"Rajeev"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Attach a callback to the Future using thenApply()</span></span><br><span class="line">CompletableFuture&lt;String&gt; greetingFuture = whatsYourNameFuture.thenApply(name -&gt; &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="string">"Hello "</span> + name;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Block and get the result of the future.</span></span><br><span class="line">System.out.println(greetingFuture.get()); <span class="comment">// Hello Rajeev</span></span><br></pre></td></tr></table></figure>
<p>你也可以通过附加一系列的<code>thenApply()</code>在回调方法 在CompletableFuture写一个连续的转换。这样的话，结果中的一个 <code>thenApply</code>方法就会传递给该系列的另外一个 <code>thenApply</code>方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture&lt;String&gt; welcomeText = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Rajeev"</span>;</span><br><span class="line">&#125;).thenApply(name -&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Hello "</span> + name;</span><br><span class="line">&#125;).thenApply(greeting -&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> greeting + <span class="string">", Welcome to the CalliCoder Blog"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(welcomeText.get());</span><br><span class="line"><span class="comment">// Prints - Hello Rajeev, Welcome to the CalliCoder Blog</span></span><br></pre></td></tr></table></figure>
<p><strong>2. thenAccept() 和 thenRun()</strong> 如果你不想从你的回调函数中返回任何东西，仅仅想在Future完成后运行一些代码片段，你可以使用<code>thenAccept()</code>和 <code>thenRun()</code>方法，这些方法经常在调用链的最末端的最后一个回调函数中使用。 <code>CompletableFuture.thenAccept()</code>持有一个<code>Consumer&lt;T&gt;</code>，返回一个<code>CompletableFuture&lt;Void&gt;</code>。它可以访问<code>CompletableFuture</code>的结果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// thenAccept() example</span></span><br><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">	<span class="keyword">return</span> ProductService.getProductDetail(productId);</span><br><span class="line">&#125;).thenAccept(product -&gt; &#123;</span><br><span class="line">	System.out.println(<span class="string">"Got product detail from remote service "</span> + product.getName())</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>虽然<code>thenAccept()</code>可以访问CompletableFuture的结果，但<code>thenRun()</code>不能访Future的结果，它持有一个Runnable返回CompletableFuture：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// thenRun() example</span></span><br><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="comment">// Run some computation  </span></span><br><span class="line">&#125;).thenRun(() -&gt; &#123;</span><br><span class="line">    <span class="comment">// Computation Finished.</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p><strong>异步回调方法的笔记</strong> CompletableFuture提供的所有回调方法都有两个变体： <code>// thenApply() variants &lt;U&gt; CompletableFuture&lt;U&gt; thenApply(Function&lt;? super T,? extends U&gt; fn) &lt;U&gt; CompletableFuture&lt;U&gt; thenApplyAsync(Function&lt;? super T,? extends U&gt; fn) &lt;U&gt; CompletableFuture&lt;U&gt; thenApplyAsync(Function&lt;? super T,? extends U&gt; fn, Executor executor)</code> 这些异步回调变体通过在独立的线程中执行回调任务帮助你进一步执行并行计算。 以下示例：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">       TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Some Result"</span></span><br><span class="line">&#125;).thenApply(result -&gt; &#123;</span><br><span class="line">    <span class="comment">/* </span></span><br><span class="line"><span class="comment">      Executed in the same thread where the supplyAsync() task is executed</span></span><br><span class="line"><span class="comment">      or in the main thread If the supplyAsync() task completes immediately (Remove sleep() call to verify)</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Processed Result"</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>在以上示例中，在<code>thenApply()</code>中的任务和在<code>supplyAsync()</code>中的任务执行在相同的线程中。任何<code>supplyAsync()</code>立即执行完成,那就是执行在主线程中（尝试删除sleep测试下）。 为了控制执行回调任务的线程，你可以使用异步回调。如果你使用<code>thenApplyAsync()</code>回调，将从<code>ForkJoinPool.commonPool()</code>获取不同的线程执行。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Some Result"</span></span><br><span class="line">&#125;).thenApplyAsync(result -&gt; &#123;</span><br><span class="line">    <span class="comment">// Executed in a different thread from ForkJoinPool.commonPool()</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Processed Result"</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>此外，如果你传入一个<code>Executor</code>到<code>thenApplyAsync()</code>回调中，，任务将从Executor线程池获取一个线程执行。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Executor executor = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Some result"</span></span><br><span class="line">&#125;).thenApplyAsync(result -&gt; &#123;</span><br><span class="line">    <span class="comment">// Executed in a thread obtained from the executor</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Processed Result"</span></span><br><span class="line">&#125;, executor);</span><br></pre></td></tr></table></figure>
<h2 id="组合两个CompletableFuture"><a href="#组合两个CompletableFuture" class="headerlink" title="组合两个CompletableFuture"></a>组合两个CompletableFuture</h2><p><strong>1. 使用 thenCompose()组合两个独立的future</strong> 假设你想从一个远程API中获取一个用户的详细信息，一旦用户信息可用，你想从另外一个服务中获取他的贷方。 考虑下以下两个方法<code>getUserDetail()</code>和<code>getCreditRating()</code>的实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">CompletableFuture&lt;User&gt; <span class="title">getUsersDetail</span><span class="params">(String userId)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">return</span> CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">		UserService.getUserDetails(userId);</span><br><span class="line">	&#125;);	</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function">CompletableFuture&lt;Double&gt; <span class="title">getCreditRating</span><span class="params">(User user)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">return</span> CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">		CreditRatingService.getCreditRating(user);</span><br><span class="line">	&#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>现在让我们弄明白当使用了<code>thenApply()</code>后是否会达到我们期望的结果-</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture&lt;CompletableFuture&lt;Double&gt;&gt; result = getUserDetail(userId)</span><br><span class="line">.thenApply(user -&gt; getCreditRating(user));</span><br></pre></td></tr></table></figure>
<p>在更早的示例中，<code>Supplier</code>函数传入<code>thenApply</code>将返回一个简单的值，但是在本例中，将返回一个CompletableFuture。以上示例的最终结果是一个嵌套的CompletableFuture。 如果你想获取最终的结果给最顶层future，使用 <code>thenCompose()</code>方法代替-</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture&lt;Double&gt; result = getUserDetail(userId)</span><br><span class="line">.thenCompose(user -&gt; getCreditRating(user));</span><br></pre></td></tr></table></figure>
<p>因此，规则就是-如果你的回调函数返回一个CompletableFuture，但是你想从CompletableFuture链中获取一个直接合并后的结果，这时候你可以使用<code>thenCompose()</code>。</p>
<p><strong>2. 使用thenCombine()组合两个独立的 future</strong> 虽然<code>thenCompose()</code>被用于当一个future依赖另外一个future的时候用来组合两个future。<code>thenCombine()</code>被用来当两个独立的<code>Future</code>都完成的时候，用来做一些事情。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(<span class="string">"Retrieving weight."</span>);</span><br><span class="line">CompletableFuture&lt;Double&gt; weightInKgFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">65.0</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Retrieving height."</span>);</span><br><span class="line">CompletableFuture&lt;Double&gt; heightInCmFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">177.8</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Calculating BMI."</span>);</span><br><span class="line">CompletableFuture&lt;Double&gt; combinedFuture = weightInKgFuture</span><br><span class="line">        .thenCombine(heightInCmFuture, (weightInKg, heightInCm) -&gt; &#123;</span><br><span class="line">    Double heightInMeter = heightInCm/<span class="number">100</span>;</span><br><span class="line">    <span class="keyword">return</span> weightInKg/(heightInMeter*heightInMeter);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Your BMI is - "</span> + combinedFuture.get());</span><br></pre></td></tr></table></figure>
<p>当两个Future都完成的时候，传给``thenCombine()的回调函数将被调用。</p>
<h2 id="组合多个CompletableFuture"><a href="#组合多个CompletableFuture" class="headerlink" title="组合多个CompletableFuture"></a>组合多个CompletableFuture</h2><p>我们使用<code>thenCompose()</code>和 <code>thenCombine()</code>把两个CompletableFuture组合在一起。现在如果你想组合任意数量的CompletableFuture，应该怎么做？我们可以使用以下两个方法组合任意数量的CompletableFuture。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">allOf</span><span class="params">(CompletableFuture&lt;?&gt;... cfs)</span></span></span><br><span class="line"><span class="function"><span class="keyword">static</span> CompletableFuture&lt;Object&gt; <span class="title">anyOf</span><span class="params">(CompletableFuture&lt;?&gt;... cfs)</span></span></span><br></pre></td></tr></table></figure>
<p><strong>1. CompletableFuture.allOf()</strong> <code>CompletableFuture.allOf</code>的使用场景是当你一个列表的独立future，并且你想在它们都完成后并行的做一些事情。</p>
<p>假设你想下载一个网站的100个不同的页面。你可以串行的做这个操作，但是这非常消耗时间。因此你想写一个函数，传入一个页面链接，返回一个CompletableFuture，异步的下载页面内容。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">CompletableFuture&lt;String&gt; <span class="title">downloadWebPage</span><span class="params">(String pageLink)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">return</span> CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">		<span class="comment">// Code to download and return the web page's content</span></span><br><span class="line">	&#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>现在，当所有的页面已经下载完毕，你想计算包含关键字<code>CompletableFuture</code>页面的数量。可以使用<code>CompletableFuture.allOf()</code>达成目的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; webPageLinks = Arrays.asList(...)	<span class="comment">// A list of 100 web page links</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Download contents of all the web pages asynchronously</span></span><br><span class="line">List&lt;CompletableFuture&lt;String&gt;&gt; pageContentFutures = webPageLinks.stream()</span><br><span class="line">        .map(webPageLink -&gt; downloadWebPage(webPageLink))</span><br><span class="line">        .collect(Collectors.toList());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Create a combined Future using allOf()</span></span><br><span class="line">CompletableFuture&lt;Void&gt; allFutures = CompletableFuture.allOf(</span><br><span class="line">        pageContentFutures.toArray(<span class="keyword">new</span> CompletableFuture[pageContentFutures.size()])</span><br><span class="line">);</span><br></pre></td></tr></table></figure>
<p>使用<code>CompletableFuture.allOf()</code>的问题是它返回CompletableFuture。但是我们可以通过写一些额外的代码来获取所有封装的CompletableFuture结果。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// When all the Futures are completed, call `future.join()` to get their results and collect the results in a list -</span></span><br><span class="line">CompletableFuture&lt;List&lt;String&gt;&gt; allPageContentsFuture = allFutures.thenApply(v -&gt; &#123;</span><br><span class="line">   <span class="keyword">return</span> pageContentFutures.stream()</span><br><span class="line">           .map(pageContentFuture -&gt; pageContentFuture.join())</span><br><span class="line">           .collect(Collectors.toList());</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>花一些时间理解下以上代码片段。当所有future完成的时候，我们调用了<code>future.join()</code>，因此我们不会在任何地方阻塞。</p>
<p><code>join()</code>方法和<code>get()</code>方法非常类似，这唯一不同的地方是如果最顶层的CompletableFuture完成的时候发生了异常，它会抛出一个未经检查的异常。</p>
<p>现在让我们计算包含关键字页面的数量。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Count the number of web pages having the "CompletableFuture" keyword.</span></span><br><span class="line">CompletableFuture&lt;Long&gt; countFuture = allPageContentsFuture.thenApply(pageContents -&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> pageContents.stream()</span><br><span class="line">            .filter(pageContent -&gt; pageContent.contains(<span class="string">"CompletableFuture"</span>))</span><br><span class="line">            .count();</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Number of Web Pages having CompletableFuture keyword - "</span> + </span><br><span class="line">        countFuture.get());</span><br></pre></td></tr></table></figure>
<p><strong>2. CompletableFuture.anyOf()</strong></p>
<p><code>CompletableFuture.anyOf()</code>和其名字介绍的一样，当任何一个CompletableFuture完成的时候【相同的结果类型】，返回一个新的CompletableFuture。以下示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture&lt;String&gt; future1 = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Result of Future 1"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">CompletableFuture&lt;String&gt; future2 = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Result of Future 2"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">CompletableFuture&lt;String&gt; future3 = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Result of Future 3"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">CompletableFuture&lt;Object&gt; anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);</span><br><span class="line"></span><br><span class="line">System.out.println(anyOfFuture.get()); <span class="comment">// Result of Future 2</span></span><br></pre></td></tr></table></figure>
<p>在以上示例中，当三个中的任何一个CompletableFuture完成， <code>anyOfFuture</code>就会完成。因为<code>future2</code>的休眠时间最少，因此她最先完成，最终的结果将是<code>future2</code>的结果。</p>
<p><code>CompletableFuture.anyOf()</code>传入一个Future可变参数，返回CompletableFuture。<code>CompletableFuture.anyOf()</code>的问题是如果你的CompletableFuture返回的结果是不同类型的，这时候你讲会不知道你最终CompletableFuture是什么类型。</p>
<h2 id="CompletableFuture-异常处理"><a href="#CompletableFuture-异常处理" class="headerlink" title="CompletableFuture 异常处理"></a>CompletableFuture 异常处理</h2><p>我们探寻了怎样创建CompletableFuture，转换它们，并组合多个CompletableFuture。现在让我们弄明白当发生错误的时候我们应该怎么做。</p>
<p>首先让我们明白在一个回调链中错误是怎么传递的。思考下以下回调链：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">	<span class="comment">// Code which might throw an exception</span></span><br><span class="line">	<span class="keyword">return</span> <span class="string">"Some result"</span>;</span><br><span class="line">&#125;).thenApply(result -&gt; &#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="string">"processed result"</span>;</span><br><span class="line">&#125;).thenApply(result -&gt; &#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="string">"result after further processing"</span>;</span><br><span class="line">&#125;).thenAccept(result -&gt; &#123;</span><br><span class="line">	<span class="comment">// do something with the final result</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>如果在原始的<code>supplyAsync()</code>任务中发生一个错误，这时候没有任何<code>thenApply</code>会被调用并且future将以一个异常结束。如果在第一个<code>thenApply</code>发生错误，这时候第二个和第三个将不会被调用，同样的，future将以异常结束。</p>
<p><strong>1. 使用 exceptionally() 回调处理异常</strong> <code>exceptionally()</code>回调给你一个从原始Future中生成的错误恢复的机会。你可以在这里记录这个异常并返回一个默认值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">Integer age = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">CompletableFuture&lt;String&gt; maturityFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span>(age &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Age can not be negative"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(age &gt; <span class="number">18</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Adult"</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Child"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;).exceptionally(ex -&gt; &#123;</span><br><span class="line">    System.out.println(<span class="string">"Oops! We have an exception - "</span> + ex.getMessage());</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Unknown!"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Maturity : "</span> + maturityFuture.get());</span><br></pre></td></tr></table></figure>
<p><strong>2. 使用 handle() 方法处理异常</strong> API提供了一个更通用的方法 - <code>handle()</code>从异常恢复，无论一个异常是否发生它都会被调用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">Integer age = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">CompletableFuture&lt;String&gt; maturityFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span>(age &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Age can not be negative"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(age &gt; <span class="number">18</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Adult"</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Child"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;).handle((res, ex) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span>(ex != <span class="keyword">null</span>) &#123;</span><br><span class="line">        System.out.println(<span class="string">"Oops! We have an exception - "</span> + ex.getMessage());</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Unknown!"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"Maturity : "</span> + maturityFuture.get());</span><br></pre></td></tr></table></figure>
<p>如果异常发生，<code>res</code>参数将是 null，否则，<code>ex</code>将是 null。</p>
<p>参考文章：</p>
<p><a href="https://juejin.im/post/5adbf8226fb9a07aac240a67" target="_blank" rel="noopener">https://juejin.im/post/5adbf8226fb9a07aac240a67</a></p>
<p><a href="http://www.importnew.com/28319.html" target="_blank" rel="noopener">http://www.importnew.com/28319.html</a></p>
<h2 id="completablefuture和parallel-stream比较"><a href="#completablefuture和parallel-stream比较" class="headerlink" title="completablefuture和parallel stream比较"></a>completablefuture和parallel stream比较</h2><p>如果你是I/O密集型的计算，可以使用自定义线程池，增加线程池大小，如果是CPU密集型计算，就不能增加比你的处理器个数再多的线程了，还是使用parallel stream比较好一些。</p>
<p>参考文章：</p>
<p><a href="https://www.jdon.com/idea/java/java-8-completablefuture-vs-parallel-stream.html" target="_blank" rel="noopener">https://www.jdon.com/idea/java/java-8-completablefuture-vs-parallel-stream.html</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/3/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/3/">3</a><span class="page-number current">4</span><a class="page-number" href="/page/5/">5</a><span class="space">&hellip;</span><a class="page-number" href="/page/21/">21</a><a class="extend next" rel="next" href="/page/5/"><i class="fa fa-angle-right"></i></a>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/images/avatar.gif"
                alt="LYJ" />
            
              <p class="site-author-name" itemprop="name">LYJ</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">21</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">5</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          

          <div class="links-of-author motion-element">
            
              
                <span class="links-of-author-item">
                  <a href="https://github.com/Colinlyj210" target="_blank" title="GitHub">
                    
                      <i class="fa fa-fw fa-github"></i>GitHub</a>
                </span>
              
                <span class="links-of-author-item">
                  <a href="mailto:blq.lyj@gmail.com" target="_blank" title="E-Mail">
                    
                      <i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                </span>
              
            
          </div>

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">LYJ</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Mist</a> v5.1.3</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  

  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
